/**
 * @author Eric Jahn Course: Object Oriented Programming Final Project Due Date:
 * August 3, 2012
 */
package oop.chat.connection;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import oop.chat.data.ConverseDB;
import oop.chat.user.Contact;
import oop.chat.user.UserAccount;
import oop.chat.user.UserType;
//import oop.chat.data.ConverseDB;

/**
 * server side of the chat
 * @author Eric Jahn
 */
public class Server implements Runnable
{
    //the server is listening to this port
    public static final int PORT = 1500;
	//login message
	public static final String LOGIN_MESSAGE = "Please login first";
	//admin account
	public static final UserAccount ADMIN = new UserAccount(UserType.ADMIN, new Contact("admin", "Spencer", "Breeden"));
	
    //server socket for the connection
    private ServerSocket socket;
    //map for all connections
    private Map<String, ClientThread> connections;
    // ConverseDB, holds all known UserAccounts and associated MessageLogs
    private ConverseDB converseB;
	//indicates whether the server is running or not
	private boolean isRunning;
	private boolean run;

    /**
     * constructor
     */
    public Server()
    {
        try
        {
            this.socket = new ServerSocket(Server.PORT);
            this.connections = (Map<String, ClientThread>) 
				Collections.synchronizedMap(new HashMap<String, ClientThread>());
            this.converseB = new ConverseDB();
			this.isRunning = false;
			this.run = true;
        }
        catch (IOException ex)
        {
            System.out.println("Error creating server: " + ex.toString());
        }
    }

	/**
	 * main method, the server runs with an infinite loop
	 */
    @Override
    public void run()
    {
		this.isRunning = true;
        while (this.run)
        {
            Socket connection = null;
            try
            {
                connection = this.socket.accept();
                if (connection != null)
                {
                    ClientThread clientThread = new ClientThread(connection, this);

                    this.connections.put(clientThread.getPID(), clientThread);
                    new Thread(clientThread).start();
                }
            }
            catch (IOException e)
            {
                System.out.println("Thread exception" + e);
                try
                {
                    connection.close();
					this.isRunning = false;
                }
                catch(Exception ex)
                {
                    System.out.println("ERROR CLOSING SOCKET" + ex.toString());
                }
            }
        }
    }
	
	/**
	 * gets the current running status of the server
	 * @return	isRunning		boolean
	 */
	public final boolean isServerRunning()
	{
		return this.isRunning;
	}
	
	/**
	 * stops the server
	 */
	public void stopServer()
	{
		this.run = false;
	}

	/**
	 * gets a specific client thread
	 * @param	PID		String
	 * @return	ClientThread
	 */
    public ClientThread getClientThread(String PID)
    {
        return this.connections.get(PID);
    }

	/**
	 * gets the converse db instance
	 * @return	converseDB
	 */
    public ConverseDB getConverseDb()
    {
        return this.converseB;
    }
    
	/**
	 * removes a client thread from the connections map
	 * @param	PID		String 
	 */
    public void removeClientThread(String PID)
    {
        this.connections.remove(PID);
    }

    /**
     * main method from the server
     *
     * @param	args	String array
     */
    public static void main(String args[])
    {
        Server server = new Server();
        server.run();
    }    
}